package com.etv.launcher.ui.component.status;

import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;

import com.etv.launcher.common.utils.UnitUtil;

/**
 * BaseStatusComponent 是一个继承自 ConstraintLayout 的自定义 Android 视图组件。
 * 该组件用于创建具有交互效果的可点击布局，具备按下和聚焦动画效果，
 * 支持按键和触摸事件，当用户按下或聚焦在组件上时，会有缩放和颜色透明度变化的动画。
 */
public class BaseStatusComponent extends ConstraintLayout {
    /**
     * 用于绘制背景的画笔
     */
    private Paint mBackgroundPaint;
    /**
     * 背景圆角的半径
     */
    private float mCornerRadius;
    /**
     * 表示组件是否被按下
     */
    private boolean mPressed;
    /**
     * 选中时的颜色
     */
    private int mSelectedColor;
    /**
     * 组件的宽度
     */
    private int mViewWidth;
    /**
     * 组件的高度
     */
    private int mViewHeight;
    /**
     * 默认的宽度和高度
     */
    private static final int DEFAULT_SIZE = 40;

    /**
     * 动画的持续时间
     */
    private static final int ANIMATION_DURATION = 400;
    /**
     * 选中颜色的十六进制字符串
     */
    private static final String SELECTED_COLOR = "#0DDDEBF8";
    /**
     * 按下时的透明度
     */
    private static final float PRESSED_ALPHA_VALUE = 0.7f;
    /**
     * 聚焦时的透明度
     */
    private static final float FOCUSED_ALPHA_VALUE = 1.0f;

    /**
     * 按下时的缩放比例
     */
    private float mPressedScale = 0.95f;
    /**
     * 用于实现按下动画的 ValueAnimator
     */
    private ValueAnimator mPressAnimator;
    /**
     * 当前的缩放比例
     */
    private float mCurrentScale = 1.0f;
    /**
     * 当前的透明度
     */
    private float mPressedAlpha = 0f;
    /**
     * 表示组件是否获得焦点
     */
    private boolean mFocused;

    /**
     * 点击事件监听器
     */
    private OnClickListener mClickListener;

    /**
     * 构造函数，使用默认的宽度和高度创建 BaseStatusComponent 实例。
     *
     * @param context 上下文对象
     */
    public BaseStatusComponent(Context context) {
        this(context, DEFAULT_SIZE, DEFAULT_SIZE);
    }

    /**
     * 构造函数，指定宽度和高度创建 BaseStatusComponent 实例。
     *
     * @param context 上下文对象
     * @param widthDp 组件的宽度，单位为 dp
     * @param heightDp 组件的高度，单位为 dp
     */
    public BaseStatusComponent(Context context, int widthDp, int heightDp) {
        super(context);
        mViewWidth = UnitUtil.dpToPx(getResources(), widthDp);
        mViewHeight = UnitUtil.dpToPx(getResources(), heightDp);
        init();
    }

    /**
     * 构造函数，从 XML 属性创建 BaseStatusComponent 实例。
     *
     * @param context 上下文对象
     * @param attrs XML 属性集合
     */
    public BaseStatusComponent(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * 构造函数，从 XML 属性和默认样式创建 BaseStatusComponent 实例。
     *
     * @param context 上下文对象
     * @param attrs XML 属性集合
     * @param defStyleAttr 默认样式属性
     */
    public BaseStatusComponent(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mViewWidth = UnitUtil.dpToPx(getResources(), DEFAULT_SIZE);
        mViewHeight = UnitUtil.dpToPx(getResources(), DEFAULT_SIZE);
        init();
    }

    /**
     * 初始化组件的属性和动画。
     */
    private void init() {
        setWillNotDraw(false); // 新增：允许父组件绘制自身内容
        mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBackgroundPaint.setStyle(Paint.Style.FILL);

        // 计算背景圆角的半径
        mCornerRadius = UnitUtil.dpToPx(getResources(), Math.min(mViewHeight, mViewWidth) * 0.1f);

        // 选中颜色
        mSelectedColor = Color.parseColor(SELECTED_COLOR);

        // 设置组件可点击和可聚焦
        setFocusable(true);
        setFocusableInTouchMode(true);
        setClickable(true);

        // 清空默认背景
        setBackground(null);

        // 初始化动画
        setupAnimators();
    }

    /**
     * 当视图的按下状态改变时调用，更新按下状态并请求重绘。
     *
     * @param pressed 是否按下
     */
    @Override
    protected void dispatchSetPressed(boolean pressed) {
        if (pressed != mPressed) {
            mPressed = pressed;
            invalidate();
        }
    }

    /**
     * 初始化按下动画的 ValueAnimator。
     */
    private void setupAnimators() {
        // 创建一个 ValueAnimator 用于实现按下动画，动画值从 0 到 1
        mPressAnimator = ValueAnimator.ofFloat(0f, 1f);
        // 设置动画的持续时间
        mPressAnimator.setDuration(ANIMATION_DURATION);
        // 设置动画的插值器
        mPressAnimator.setInterpolator(new DecelerateInterpolator());

        // 添加动画更新监听器，根据动画值更新缩放比例和透明度
        mPressAnimator.addUpdateListener(animation -> {
            float fraction = (float) animation.getAnimatedValue();
            if (mPressed) {
                mCurrentScale = 1f - (1f - mPressedScale) * fraction;
                if (!mFocused) {
                    mPressedAlpha = fraction * PRESSED_ALPHA_VALUE;
                }
            } else {
                mCurrentScale = mPressedScale + (1f - mPressedScale) * fraction;
                if (!mFocused) {
                    // 直接从当前 alpha 值开始渐变到 0
                    mPressedAlpha = (1f - fraction) * mPressedAlpha;
                }
            }
            // 请求重绘视图
            invalidate();
        });
    }

    /**
     * 处理按键按下事件，当按下 ENTER 或 DPAD_CENTER 键时，启动按下动画。
     *
     * @param keyCode 按键码
     * @param event 按键事件对象
     * @return 如果事件被处理返回 true，否则返回父类的处理结果
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            if (!mPressed) {
                mPressed = true;
                startPressAnimation(true);
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * 处理按键释放事件，当释放 ENTER 或 DPAD_CENTER 键时，启动释放动画并执行点击事件。
     *
     * @param keyCode 按键码
     * @param event 按键事件对象
     * @return 如果事件被处理返回 true，否则返回父类的处理结果
     */
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            if (mPressed) {
                mPressed = false;
                startPressAnimation(false);
                performClick();
                return true;
            }
        }
        return super.onKeyUp(keyCode, event);
    }

    /**
     * 处理焦点变化事件，更新焦点状态，取消动画并重置状态。
     *
     * @param gainFocus 是否获得焦点
     * @param direction 焦点移动的方向
     * @param previouslyFocusedRect 之前有焦点的矩形区域
     */
    @Override
    @SuppressLint("MissingSuperCall")
    protected void onFocusChanged(boolean gainFocus, int direction, @Nullable Rect previouslyFocusedRect) {
        mFocused = gainFocus;
        if (mPressAnimator.isRunning()) {
            mPressAnimator.cancel();
        }
        // 失去焦点时重置所有状态
        if (!gainFocus) {
            mPressed = false;
            mPressedAlpha = 0f;
            mCurrentScale = 1.0f;
        }
        // 请求重绘视图
        invalidate();
    }

    /**
     * 处理触摸事件，根据触摸动作更新按下状态，启动相应的动画并执行点击事件。
     *
     * @param event 触摸事件对象
     * @return 如果事件被处理返回 true
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 请求焦点，这会导致之前有焦点的视图失去焦点
                requestFocus();
                mPressed = true;
                startPressAnimation(true);
                break;
            case MotionEvent.ACTION_UP:
                if (mPressed) {
                    mPressed = false;
                    startPressAnimation(false);
                    performClick();
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                mPressed = false;
                startPressAnimation(false);
                break;
        }
        return true;
    }

    /**
     * 启动按下或释放动画。
     *
     * @param pressed 是否按下
     */
    private void startPressAnimation(boolean pressed) {
        if (mPressAnimator != null) {
            // 保存当前的 alpha 值，用于平滑过渡
            float currentAlpha = mPressedAlpha;
            mPressAnimator.cancel();

            // 设置初始 alpha 值
            if (!pressed) {
                mPressedAlpha = currentAlpha;
            }

            if (pressed) {
                mPressAnimator.setFloatValues(0f, 1f);
            } else {
                mPressAnimator.setFloatValues(0f, 1f); // 总是从 0 到 1，区别在于动画更新时的计算
            }
            mPressAnimator.start();
        }
    }

    /**
     * 执行点击事件，如果设置了点击事件监听器，则调用监听器的 onClick 方法。
     *
     * @return 点击事件是否被处理
     */
    @Override
    public boolean performClick() {
        super.performClick();
        if (mClickListener != null) {
            mClickListener.onClick(this);
        }
        return true;
    }

    /**
     * 绘制视图的背景和子视图，根据按下和焦点状态进行缩放和绘制背景。
     *
     * @param canvas 画布对象
     */
    /**
     * 绘制父组件的背景（缩放效果和选中状态）
     */
    @Override
    protected void onDraw(Canvas canvas) {
        drawParentBackground(canvas);
        super.onDraw(canvas); // 可选：如果父类有需要绘制的内容
    }

    /**
     * 绘制背景（带缩放效果）
     */
    private void drawParentBackground(Canvas canvas) {
        canvas.save();

        // 应用缩放（仅影响背景）
        if (mPressed || mCurrentScale != 1.0f) {
            float px = getWidth() / 2f;
            float py = getHeight() / 2f;
            canvas.scale(mCurrentScale, mCurrentScale, px, py);
        }

        // 绘制背景
        if (mFocused || mPressed || mPressedAlpha > 0.01f) {
            mBackgroundPaint.setColor(mSelectedColor);
            float alpha = mFocused ? FOCUSED_ALPHA_VALUE : mPressedAlpha;
            mBackgroundPaint.setAlpha((int) (255 * alpha));
            canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
                    mCornerRadius, mCornerRadius, mBackgroundPaint);
        }

        canvas.restore();
    }

    /**
     * 移除原 dispatchDraw() 中的背景绘制代码
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas); // 仅绘制子视图
    }

    /**
     * 当视图从窗口中分离时，取消动画并释放资源。
     */
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mPressAnimator != null) {
            mPressAnimator.cancel();
            mPressAnimator = null;
        }
    }

    /**
     * 设置点击事件监听器。
     *
     * @param listener 点击事件监听器
     */
    @Override
    public void setOnClickListener(OnClickListener listener) {
        mClickListener = listener;
    }
}